//3.执行上下文

// 可执行代码(executable code)的类型

//1.全局代码
let a = 1;
//位于最外层，不在任何函数内部的代码。
//执行时会创建全局执行上下文（Global Execution Context）

//2.函数代码
//位于函数内部的代码  a= 3;
//每次调用函数时，都会创建一个新的函数执行上下文（Function Execution Context）
function test(){
    a= 3;
};

//3.eval代码
//在 eval() 函数内部运行的代码字符串
//执行时会创建 Eval 执行上下文（但在严格模式下，eval 代码会有自己的词法环境，非严格模式下可能影响调用方环境）
eval("let b = 1;")

//执行上下文: javascript引擎一段一段的分析执行代码时进行的准备工作

//执行上下文栈: JavaScript 引擎创建了执行上下文栈（Execution context stack，ECS）来管理执行上下文


//举例分析执行上下文栈
function fun3() {
    console.log('fun3')
}

function fun2() {
    fun3();
}

function fun1() {
    fun2();
}

fun1();

//1.全局执行上下文
/*在代码执行前,javascript引擎创建全局执行上下文并放入调用栈
* 1.创建阶段(变量环境、词法环境、this指向:严格模式下为undefined,非严格模式下为window)
*函数fun3、fun2、fun1被初始化
* fun3 <Function>
* fun2 <Function>
* fun1 <Function>
* 2.执行阶段(顺序执行)
* 遇到fun1();调用fun1函数,创建fun1的函数执行上下文
* */

//2.调用fun1
/*
* 1.创建fun1的函数执行上下文,压入调用栈
* 2.控制器转到fun1的函数体内部
* 3.执行fun1函数体中的fun2()
* 4.创建fun2的函数执行上下文
* */

//3.调用fun2
/*
* 1.暂停执行fun1,fun1的函数执行上下文保持在调用栈中
* 2.创建fun2的函数执行上下文,压入调用栈
* 3.控制器转到fun2的函数体内部
* 4.执行fun2函数体中的fun3()
* 5.创建fun3的函数执行上下文
* */

//4.调用fun3
/*
* 1.暂停执行fun2,fun2的函数执行上下文保持在调用栈中
* 2.创建fun3的函数执行上下文,压入调用栈
* 3.控制器转到fun3的函数体内部
* 4.执行fun3函数体体  ”console.log('fun3')“
* 5.fun3的函数执行完成后，将fun3的函数执行上下文从调用栈中弹出
* */

//5.回到fun2
/* 1.fun3的函数体执行完成后，回到fun2的执行上下文继续执行
*  2.fun2函数的函数体后面没有其他执行语句，fun2执行完毕，弹出调用栈中的fun2函数执行上下文
* */

//6.回到fun1
/* 1.fun2的函数体执行完成后，回到fun1的执行上下文继续执行
*  2.fun1函数的函数体后面没有其他执行语句，fun1执行完毕，弹出调用栈中的fun1函数执行上下文
* */

//7.回到全局执行上下文
/*
* 所有函数调用结束，全局代码执行完毕
* 全局执行上下文可能保留（比如在浏览器中直到关闭标签页才销毁），但调用栈中只剩下全局上下文
* */

// 执行上下文栈变化图
/*
*   调用栈(底部===》顶部)       变化
*    [全局]                   开心执行代码
*    [全局,fun1]              调用fun1函数，向调用栈中压入fun1函数执行上下文
*    [全局,fun1,fun2]         暂停fun1函数执行,调用fun2函数,向调用栈中压入fun2函数执行上下文
*    [全局,fun1,fun2,fun3]    暂停fun2函数执行,调用fun3函数,向调用栈中压入fun3函数执行上下文
*    [全局,fun1,fun2]         fun3函数执行完毕返回fun2,调用栈中弹出fun3函数执行上下文
*    [全局,fun1]              fun2函数执行完毕返回fun1,调用栈中弹出fun2函数执行上下文
*    [全局]                   fun1函数执行完毕返回全局上下文,调用栈中弹出fun1函数执行上下文
* */